using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using ASPItalia.ModelVirtualCasting.WPF.ViewModels;

namespace ASPItalia.ModelVirtualCasting.WPF.DragDrop
{
    /// <summary>
    /// Class that act as drag'n'drop target element manager for current ModelViewModel
    /// </summary>
    public class ModelDragTargetAdvisor : IDropTargetAdvisor
    {
        private UIElement _targetUI;

        public ModelDragTargetAdvisor()
        {

        }

        /// <summary>
        /// Rappresent the target uielement to use for specific element
        /// </summary>
        public static readonly DependencyProperty DropTargetProperty = DependencyProperty.RegisterAttached("DropTarget", typeof(UIElement), typeof(ModelDragTargetAdvisor));

        /// <summary>
        /// Method to set the drop target
        /// </summary>
        /// <param name="depObj">Dependency object</param>
        /// <param name="target">The target of the drop action</param>
        public static void SetDropTarget(DependencyObject depObj, ItemsControl target)
        {
            depObj.SetValue(DropTargetProperty, target);
        }

        /// <summary>
        /// Method to get the drop target
        /// </summary>
        /// <param name="depObj">Dependency object</param>
        /// <returns>The drop target</returns>
        public static ItemsControl GetDropTarget(DependencyObject depObj)
        {
            return (ItemsControl) depObj.GetValue(DropTargetProperty);
        }

        /// <summary>
        /// Get if drag'n'drop operation contains valid data
        /// </summary>
        /// <param name="obj">Clipboard dataobject</param>
        /// <returns></returns>
        public virtual bool IsValidDataObject(IDataObject obj)
        {
            if (obj.GetDataPresent(DataFormats.Serializable))
            {
                object item = obj.GetData(DataFormats.Serializable);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Called when drop operation is finished. It adds item to target element
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="dropPoint"></param>
        public virtual void OnDropCompleted(IDataObject obj, Point dropPoint)
        {
            object item = obj.GetData(DataFormats.Serializable);

            // Try to get target items control
            UIElement element = GetDropTarget(this.TargetUI);

            if (element == null)
                element = (UIElement) this.TargetUI;

            ViewModelsContext.Current.MainViewModel.CurrentModel = (ModelViewModel)item;
        }   

        /// <summary>
        /// Get or set target drag'n'drop operation
        /// </summary>
        public UIElement TargetUI
        {
            get { return _targetUI; }
            set { _targetUI = value; }
        }

        /// <summary>
        /// Return the element rappresenting visual feedback during drag'n'drop operation
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public UIElement GetVisualFeedback(IDataObject obj)
        {
            ContentControl uiItem = ExtractElement(obj);
            if (uiItem == null) return null;
            UIElement elt = VisualTreeHelper.GetChild(uiItem, 0) as UIElement;

            Rectangle rect = new Rectangle();
            rect.Width = elt.RenderSize.Width;
            rect.Height = elt.RenderSize.Height;
            rect.Opacity = 0.7d;

            VisualBrush brush = new VisualBrush(elt);
            //brush.Stretch = Stretch.None;
            //brush.ViewboxUnits = BrushMappingMode.Absolute;
            //brush.Viewbox = new Rect(new Point(0, 0), elt.RenderSize);
            rect.Fill = brush;
            rect.IsHitTestVisible = false;

            RenderOptions.SetCachingHint(rect, CachingHint.Cache);
            RenderOptions.SetCachingHint(brush, CachingHint.Cache);

            return rect;
        }

        /// <summary>
        /// Return the target drop mouse application point
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public Point GetOffsetPoint(IDataObject obj)
        {
            Point p = (Point) obj.GetData("point");
            return p;
        }

        private ContentControl ExtractElement(IDataObject obj)
        {
            return obj.GetData(DataFormats.Locale) as ContentControl;
        }
    }
}